home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / ge_cool.lha / GE_COOL2.1 / cpp / cpp2.c < prev    next >
C/C++ Source or Header  |  1992-04-13  |  25KB  |  902 lines

  1. /*
  2.  
  3.  
  4.  Copyright (C) 1990 Texas Instruments Incorporated.
  5.  
  6.  Permission is granted to any individual or institution to use, copy, modify,
  7.  and distribute this software, provided that this complete copyright and
  8.  permission notice is maintained, intact, in all copies and supporting
  9.  documentation.
  10.  
  11.  Texas Instruments Incorporated provides this software "as is" without
  12.  express or implied warranty.
  13.  
  14.  
  15.  *                C P P 2 . C
  16.  *
  17.  *               Process #control lines
  18.  *
  19.  * Edit history
  20.  * 13-Nov-84    MM    Split from cpp1.c
  21.  * 21-Oct-85    RMS    Do not turn on `instring' while reading #include arg.
  22.  *            Rename `token' to `tokenbuf'.
  23.  *            Flush tabs at end of #include line, like spaces.
  24.  * 16-Mar-89    LGO    Split parse_file out from doinclude, so it can be 
  25.  *                      shared by #pragma demacro.
  26.  * 20-Mar-89    LGO    Ignore command errors in non-compiled code
  27.  * 23-Mar-89    LGO    Add support for #error
  28.  * 24-Sep-89    AFM     OS2, XENIX and AIX support.
  29.  * 19-Jan-90    DKM     MVS support 
  30.  * 23-Apr-90    MJF     Include file parsing ignore // or /* as comment
  31.  * 01-May-90    MJF     unrecognized #pragma needs to output newline
  32.  * 18-May-90    MBN     Conditional compilation for COOL to get "clean" cpp
  33.  * 25-Jun-91    GPD    Remove #elif to make more portable.
  34.  *            Added support for Interactive Unix.
  35.  * 01-Jul-91    GPD    Fix search for include in local directory first.
  36.  */
  37.  
  38. #include    <stdio.h>
  39. #include    <ctype.h>
  40. #include    "cppdef.h"
  41. #include    "cpp.h"
  42.  
  43. #if defined(vms)
  44. #include        <types.h>
  45. #else
  46. #if !defined(SYS_OSVS)
  47. #include        <sys/types.h>
  48. #endif
  49. #endif
  50.  
  51. #if defined(vms)
  52. #include        <file.h>
  53. #else
  54. #if defined(SYS_OSVS)
  55. #include        <fcntl.h>
  56. #else
  57. #if !defined(DOS) && !defined(MSDOS)
  58. #if defined(M_INTERACTIVE)
  59. #include    <unistd.h>
  60. #endif
  61. #include        <sys/file.h>
  62. #endif
  63. #endif
  64. #endif
  65.  
  66. #if defined(vms)
  67. /*
  68.  * Include the rms stuff.  (We can't just include rms.h as it uses the
  69.  * VaxC-specific library include syntax that Decus CPP doesn't support.
  70.  * By including things by hand, we can CPP ourself.)
  71.  */
  72. #include    <nam.h>
  73. #include    <fab.h>
  74. #include    <rab.h>
  75. #include    <rmsdef.h>
  76. #endif
  77.  
  78. #ifdef COOL
  79. extern void define_external();      /* Define an external macro handler */
  80. #endif
  81.  
  82. /*
  83.  * Generate (by hand-inspection) a set of unique values for each control
  84.  * operator.  Note that this is not guaranteed to work for non-Ascii
  85.  * machines.  CPP won't compile if there are hash conflicts.
  86.  */
  87.  
  88. #define    L_assert    ('a' + ('s' << 1))
  89. #define    L_define    ('d' + ('f' << 1))
  90. #define    L_elif        ('e' + ('i' << 1))
  91. #define    L_else        ('e' + ('s' << 1))
  92. #define    L_endif        ('e' + ('d' << 1))
  93. #define    L_if        ('i' + (EOS << 1))
  94. #define    L_ifdef        ('i' + ('d' << 1))
  95. #define    L_ifndef    ('i' + ('n' << 1))
  96. #define    L_include    ('i' + ('c' << 1))
  97. #define    L_line        ('l' + ('n' << 1))
  98. #define    L_nogood    (EOS + (EOS << 1))    /* To catch #i        */
  99. #define    L_pragma    ('p' + ('a' << 1))
  100. #define    L_error     ('e' + ('r' << 1))
  101. #define L_undef        ('u' + ('d' << 1))
  102. #if DEBUG
  103. #define    L_debug        ('d' + ('b' << 1))    /* #debug        */
  104. #define    L_nodebug    ('n' + ('d' << 1))    /* #nodebug        */
  105. #endif
  106.  
  107. int
  108. control(counter)
  109. int        counter;    /* Pending newline counter        */
  110. /*
  111.  * Process #control lines.  Simple commands are processed inline,
  112.  * while complex commands have their own subroutines.
  113.  *
  114.  * The counter is used to force out a newline before #line, and
  115.  * #pragma commands.  This prevents these commands from ending up at
  116.  * the end of the previous line if cpp is invoked with the -C option.
  117.  */
  118. {
  119.     register int        c;
  120.     register char        *tp;
  121.     register int        hash;
  122.     char            *ep;
  123.  
  124.     /* Copy all #xxx commands to output as comments */
  125.     if (debug&2 && compiling && cflag) {
  126.       char* bufp = infile->bptr;
  127.       fputs("\n//#",stdout);
  128.       while(*bufp != '\n' && *bufp != EOS)
  129.         output(*bufp++);
  130.     }
  131.  
  132.     c = skipws();
  133.     if (c == '\n' || c == EOF_CHAR)
  134.         return (counter + 1);
  135.     if (!isdigit(c))
  136.         scanid(c);            /* Get #word to tokenbuf    */
  137.     else {
  138.         unget();            /* Hack -- allow #123 as a    */
  139.         strcpy(tokenbuf, "line");    /* synonym for #line 123    */
  140.     }
  141.     hash = (tokenbuf[1] == EOS) ? L_nogood : (tokenbuf[0] +
  142.                           (tokenbuf[2] << 1));
  143.     switch (hash) {
  144.     case L_assert:    tp = "assert";        break;
  145.     case L_define:    tp = "define";        break;
  146.     case L_elif:    tp = "elif";        break;
  147.     case L_else:    tp = "else";        break;
  148.     case L_endif:    tp = "endif";        break;
  149.     case L_if:    tp = "if";        break;
  150.     case L_ifdef:    tp = "ifdef";        break;
  151.     case L_ifndef:    tp = "ifndef";        break;
  152.     case L_include:    tp = "include";        break;
  153.     case L_line:    tp = "line";        break;
  154.     case L_pragma:    tp = "pragma";        break;
  155.     case L_error:    tp = "error";        break;
  156.     case L_undef:    tp = "undef";        break;
  157. #if DEBUG
  158.     case L_debug:    tp = "debug";        break;
  159.     case L_nodebug:    tp = "nodebug";        break;
  160. #endif
  161.     default:    hash = L_nogood;
  162.     case L_nogood:    tp = "";        break;
  163.     }
  164.     if (!streq(tp, tokenbuf))
  165.         hash = L_nogood;
  166.     /*
  167.      * hash is set to a unique value corresponding to the
  168.      * control keyword (or L_nogood if we think it's nonsense).
  169.      */
  170. #ifdef PARANOID
  171.     if (infile->fp == NULL)
  172.         cwarn("Control line \"%s\" within macro expansion", tokenbuf);
  173. #endif
  174.     if (!compiling) {            /* Not compiling now    */
  175.         switch (hash) {
  176.         case L_if:                /* These can't turn    */
  177.         case L_ifdef:            /*  compilation on, but    */
  178.         case L_ifndef:            /*   we must nest #if's    */
  179.         if (++ifptr >= &ifstack[BLK_NEST])
  180.             goto if_nest_err;
  181.         *ifptr = 0;            /* !WAS_COMPILING    */
  182.         case L_line:            /* Many            */
  183.         case L_pragma:            /*  options        */
  184.         case L_include:            /*   are uninteresting    */
  185.         case L_define:            /*    if we        */
  186.         case L_undef:            /*     aren't        */
  187.         case L_assert:            /*      compiling.    */
  188.         case L_error:
  189.         case L_nogood:
  190. dump_line:    skipnl();            /* Ignore rest of line    */
  191.         return (counter + 1);
  192.         }
  193.     }
  194.     /*
  195.      * Make sure that #line and #pragma are output on a fresh line.
  196.      */
  197.     if (counter > 0 && (hash == L_line || hash == L_pragma)) {
  198.         putchar('\n');
  199.         counter--;
  200.     }
  201.     switch (hash) {
  202.     case L_line:
  203.         /*
  204.          * Parse the line to update the line number and "progname"
  205.          * field and line number for the next input line.
  206.          * Set wrongline to force it out later.
  207.          */
  208.         c = skipws();
  209.         workp = work;            /* Save name in work    */
  210.         while (c != '\n' && c != EOF_CHAR) {
  211.         save(c);
  212.         c = get();
  213.         }
  214.         unget();              /* put the newline back */
  215.         save(EOS);
  216.         /*
  217.          * Split #line argument into <line-number> and <name>
  218.          * We subtract 1 as we want the number of the next line.
  219.          */
  220.         line = atoi(work);            /* Reset line number    */
  221.         for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
  222.         ;                /* Skip over digits    */
  223.         if (*tp != EOS) {            /* Got a filename, so:    */
  224.         if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
  225.             tp++;            /* Skip over left quote    */
  226.             *ep = EOS;            /* And ignore right one    */
  227.         }
  228.         if (infile->progname != NULL)    /* Give up the old name    */
  229.             free(infile->progname);    /* if it's allocated.    */
  230.             infile->progname = savestring(tp);
  231.         }
  232.         if (infile->fp == NULL) {        /* If inside a macro */
  233.           printf("#%s %d \"%s\"\n", LINE_PREFIX, line,
  234.              (infile->progname != NULL)
  235.              ? infile->progname : infile->filename);
  236.           counter--;          /* Subtract for the \n added later */
  237.           wrongline = FALSE;
  238.         } else {
  239.           wrongline = TRUE;          /* else Force output later */
  240.           line--;
  241.         }
  242.         break;
  243.  
  244.     case L_include:
  245.         doinclude();
  246.         break;
  247.  
  248.     case L_define:
  249.         dodefine();
  250.         break;
  251.  
  252.     case L_undef:
  253.         doundef();
  254.         break;
  255.  
  256.     case L_else:
  257.         if (ifptr == &ifstack[0])
  258.         goto nest_err;
  259.         else if ((*ifptr & ELSE_SEEN) != 0)
  260.         goto else_seen_err;
  261.         *ifptr |= ELSE_SEEN;
  262.         if ((*ifptr & WAS_COMPILING) != 0) {
  263.         if (compiling || (*ifptr & TRUE_SEEN) != 0)
  264.             compiling = FALSE;
  265.         else {
  266.             compiling = TRUE;
  267.         }
  268.         }
  269.         break;
  270.  
  271.     case L_elif:
  272.         if (ifptr == &ifstack[0])
  273.         goto nest_err;
  274.         else if ((*ifptr & ELSE_SEEN) != 0) {
  275. else_seen_err:    cerror("#%s may not follow #else", tokenbuf);
  276.         goto dump_line;
  277.         }
  278.         if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
  279.         compiling = FALSE;        /* Done compiling stuff    */
  280.         goto dump_line;            /* Skip this clause    */
  281.         }
  282.         doif(L_if);
  283.         break;
  284.  
  285.     case L_if:
  286.     case L_ifdef:
  287.     case L_ifndef:
  288.         if (++ifptr >= &ifstack[BLK_NEST])
  289. if_nest_err:    cfatal("Too many nested #%s statements", tokenbuf);
  290.         *ifptr = WAS_COMPILING;
  291.         doif(hash);
  292.         break;
  293.  
  294.     case L_endif:
  295.         if (ifptr == &ifstack[0]) {
  296. nest_err:    cerror("#%s must be in an #if", tokenbuf);
  297.         goto dump_line;
  298.         }
  299.         if (!compiling && (*ifptr & WAS_COMPILING) != 0)
  300.         wrongline = TRUE;
  301.         compiling = ((*ifptr & WAS_COMPILING) != 0);
  302.         --ifptr;
  303.         break;
  304.  
  305.     case L_assert:
  306.         if (eval() == 0)
  307.         cerror("Preprocessor assertion failure", NULLST);
  308.         break;
  309.  
  310.     case L_pragma:
  311.         /*
  312.          * #pragma is provided to pass "options" to later
  313.          * passes of the compiler.  cpp only has one: defmacro
  314.          */
  315.         c=skipws();
  316.         c = macroid(c);
  317. #ifdef COOL
  318.         if(strcmp(tokenbuf, "defmacro") == 0) {
  319.           define_external();
  320.  
  321. #if (HOST == SYS_XENIX || HOST == SYS_OS2)
  322. /*
  323.  * munge pack(n) for Xenix and os2 Glockenspiels cfront by quotifying 
  324.  * pack(n) to "pack(n)"
  325.  */
  326.         } else if (strcmp(tokenbuf, "pack") == 0) {
  327.           fputs("#pragma \"", stdout);
  328.           while (c != '\n' && c != EOF_CHAR) {
  329.         if (type[c] == LET) {
  330.           fputs(tokenbuf, stdout);
  331.         } else cput(c);
  332.         c = get();
  333.         c = macroid(c);
  334.           }
  335.           putchar('"');
  336.           unget();              /* Leave newline in buffer */
  337. #endif
  338.         } else
  339. #endif
  340.         { /* pass through undefined pragmas */
  341.           fputs("#pragma ", stdout);
  342.           while (c != '\n' && c != EOF_CHAR) {
  343.         if (type[c] == LET) {
  344.           fputs(tokenbuf, stdout);
  345.         } else cput(c);
  346.         c = get();
  347.         c = macroid(c);
  348.           }
  349.           putchar('\n');          /* output newline */
  350.           unget();              /* Leave newline in buffer */
  351.         }
  352.         break;
  353.  
  354.       case L_error:
  355.         workp = work;
  356.         for(c=skipws(); c!='\n' && c!=EOF_CHAR; c=get())
  357.           *workp++ = c;          
  358.         *workp = EOS;
  359.         unget();
  360.         cerror(work, NULLST);
  361.         break;
  362.  
  363. #if DEBUG
  364.     case L_debug:
  365.         if (debug == 0)
  366.         dumpdef("debug set on");
  367.         debug++;
  368.         break;
  369.  
  370.     case L_nodebug:
  371.         debug--;
  372.         break;
  373. #endif
  374.  
  375.     default:
  376.         /*
  377.          * Undefined #control keyword.
  378.          * Note: the correct behavior may be to warn and
  379.          * pass the line to a subsequent compiler pass.
  380.          * This would allow #asm or similar extensions.
  381.          */
  382.         cerror("Illegal # command \"%s\"", tokenbuf);
  383.         break;
  384.     }
  385.     if (hash != L_include) {
  386. #if OLD_PREPROCESSOR
  387.         /*
  388.          * Ignore the rest of the #control line so you can write
  389.          *        #if    foo
  390.          *        #endif    foo
  391.          */
  392.         goto dump_line;            /* Take common exit    */
  393. #else
  394.         switch (hash) {
  395.         case L_else:
  396.         case L_endif:
  397.           goto dump_line;            /* Take common exit    */
  398.         default:
  399.           if (skipws() != '\n') {
  400.         cwarn("Unexpected text in #control line ignored", NULLST);
  401.         skipnl();
  402.           }
  403.         }
  404. #endif
  405.     }
  406.     return (counter + 1);
  407. }
  408.  
  409. FILE_LOCAL
  410. doif(hash)
  411. int        hash;
  412. /*
  413.  * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
  414.  * while #if needs a subroutine of its own to evaluate the expression.
  415.  *
  416.  * doif() is called only if compiling is TRUE.  If false, compilation
  417.  * is always supressed, so we don't need to evaluate anything.  This
  418.  * supresses unnecessary warnings.
  419.  */
  420. {
  421.     register int        c;
  422.     register int        found;
  423.  
  424.     if ((c = skipws()) == '\n' || c == EOF_CHAR) {
  425.         unget();
  426.         goto badif;
  427.     }
  428.     if (hash == L_if) {
  429.         unget();
  430.         found = (eval() != 0);    /* Evaluate expr, != 0 is  TRUE    */
  431.         hash = L_ifdef;        /* #if is now like #ifdef    */
  432.     }
  433.     else {
  434.         if (type[c] != LET)        /* Next non-blank isn't letter    */
  435.         goto badif;        /* ... is an error        */
  436.         found = (lookid(c) != NULL); /* Look for it in symbol table    */
  437.     }
  438.     if (found == (hash == L_ifdef)) {
  439.         compiling = TRUE;
  440.         *ifptr |= TRUE_SEEN;
  441.     }
  442.     else {
  443.         compiling = FALSE;
  444.     }
  445.     return(0);
  446.  
  447. badif:    cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
  448. #if !OLD_PREPROCESSOR
  449.     skipnl();                /* Prevent an extra    */
  450.     unget();                /* Error message    */
  451. #endif
  452.     return(0);
  453. }
  454.  
  455. /*
  456.  * Parse the file name in the #INCLUDE control line.
  457.  * Leave the file name in work, and return the terminating delimiter
  458.  * which is " or >. Returns EOS on error.
  459.  */
  460. int
  461. parse_include()
  462. {
  463.     register int        c;
  464.     register int        delim;
  465.  
  466.     delim = macroid(skipws());
  467.     if (delim != '<' && delim != '"') {
  468.       strcpy(work, tokenbuf);
  469. #if HOST == SYS_VMS
  470.       return(' ');
  471. #else
  472.       return(EOS);
  473. #endif
  474.     }
  475.     if (delim == '<')
  476.         delim = '>';
  477.     workp = work;
  478.                                     /* Grab the file name           */
  479.         instring = TRUE;        /* ignore comment chars in filename */
  480.     while ((c = get()) != delim) {
  481.       if(c=='\n' || c == EOF_CHAR) {
  482.         instring = FALSE;
  483.         return(EOS); /* Missing delimiter */
  484.       }
  485.       else 
  486.         save(c);            /* Put it away.            */
  487.     }
  488.         instring = FALSE;
  489.     *workp = EOS;            /* Terminate filename        */
  490.     return(delim);
  491. }
  492.  
  493. FILE_LOCAL
  494. doinclude()
  495. /*
  496.  * Process the #include control line.
  497.  * There are three variations:
  498.  *    #include "file"        search somewhere relative to the
  499.  *                current source file, if not found,
  500.  *                treat as #include <file>.
  501.  *    #include <file>        Search in an implementation-dependent
  502.  *                list of places.
  503.  *    #include token        Expand the token, it must be one of
  504.  *                "file" or <file>, process as such.
  505.  *
  506.  * Note: the November 12 draft forbids '>' in the #include <file> format.
  507.  * This restriction is unnecessary and not implemented.
  508.  */
  509. {
  510.   register int        c;
  511.   register int        delim;
  512. #ifdef VMS
  513.   char                  def_filename[NAM$C_MAXRSS + 1];
  514. #endif
  515.   /* Get the file name into work  */
  516.   if((delim = parse_include()) == EOS) goto incerr;
  517.   c = skipws();
  518.   if (c != '\n' && c != EOF_CHAR)
  519.     goto incerr;         /* Ensure nothing else to end of the line. */
  520.   unget();             /* Force nl after include                 */
  521. #if HOST == SYS_VMS
  522.   /*
  523.    * Assume the default .h filetype.
  524.    */
  525.   if (!vmsparse(work, ".H", def_filename)) {
  526.     perror(work);              /* Oops.            */
  527.     goto incerr;
  528.   }
  529. #endif
  530.  
  531. #if HOST == SYS_MVS
  532.   if (findinclude_mvs(work, R_OK) == FALSE)
  533.     goto openerr;
  534. #else
  535.   if (findinclude(work, (delim == '"'), R_OK) == FALSE)
  536.     goto openerr;
  537. #endif
  538.   /*
  539.    * Actually open the include file
  540.    */
  541.  
  542.   if (debug&1) {
  543.     FILEINFO* file;              /* DEBUG */
  544.     fprintf(stderr, "Line %4d", line);
  545.     for(file = infile; file != NULL; file = file->parent)
  546.       if(file->fp != NULL) fprintf(stderr, "  ");
  547.     fprintf(stderr, "#include %s\n", work);
  548.   }
  549.   if (openfile(work))
  550.     return(0);
  551.   /*
  552.    * No sense continuing if #include file isn't there.
  553.    */
  554.  openerr:
  555.    cfatal("Cannot open include file \"%s\"", work);
  556.         
  557.  incerr:    cerror("#include syntax error", NULLST);
  558.   return(0);
  559. }
  560.  
  561.  
  562. #if HOST == SYS_OS2
  563. /* 
  564.  * Ensure dir names and filename is less than 8 characters long
  565.  */
  566. char* truncate_filename(filename) 
  567.   char* filename;
  568. {
  569.   char* p = filename;
  570.   int   name_len = 0;
  571.   char* dot;
  572.   int   slash;
  573.  
  574.   slash = strcspn(p,"/\\");
  575.   while (strlen(p) != slash)
  576.     {
  577.      if (slash == 0)    /* slash at start of name */
  578.         slash = strcspn(++p,"/\\");
  579.  
  580.      if (strlen(p) != slash)  /* slash found */
  581.        {
  582.         if (slash < 9)        /* dir name within bounds */
  583.            p += slash + 1;
  584.         else                  /* else trnucate to eight */
  585.       {
  586.            strcpy(p+8,p+slash);
  587.            p += slash + 1;
  588.      }
  589.         slash = strcspn(p,"/\\");  /* find next slash */
  590.       }
  591.    }
  592.  
  593.   dot = strchr(filename, '.');
  594.   if (dot != NULL) {
  595.     p = dot -1;
  596.     while (p >= filename && type[*p]==LET) p--, name_len++;
  597.     if (name_len > 8)
  598.       strcpy(p+9, dot);
  599.   }
  600.   return filename;
  601. }
  602. #endif
  603.  
  604. int
  605. findinclude(filename, searchlocal, permissions)
  606. char        *filename;        /* Input file name        */
  607. int        searchlocal;        /* TRUE if #include "file"    */
  608. int             permissions;            /* std permission flags, R_OK, etc */
  609. /*
  610.  * Find an include file.  This routine is only called from
  611.  * doinclude() above, but was written as a separate subroutine for
  612.  * programmer convenience.  It searches the list of directories
  613.  * and modifies filename to contain the entire pathname.
  614.  * Returns TRUE if the file was found, else FALSE.
  615.  * No error message is printed.
  616.  */
  617. {
  618.     register char        **incptr;
  619. #if HOST == SYS_VMS
  620. #if NBUFF < (NAM$C_MAXRSS + 1)
  621.     << error, NBUFF isn't greater than NAM$C_MAXRSS >>
  622. #endif
  623. #endif
  624.     char            tmpname[NBUFF];    /* Filename work area    */
  625.  
  626.  
  627. #if HOST == SYS_OS2
  628. #  if defined(SHORTFILE)
  629. /*
  630.  * For OS/2 truncate file name to 8.3 format for DOS partition if needed.
  631.  */
  632.    truncate_filename(filename);
  633. #  endif
  634. #endif
  635.  
  636.     if (searchlocal) {
  637.         /*
  638.          * Look in local directory first
  639.          */
  640.         if (!hasdirectory(filename, tmpname, TRUE)
  641.          && hasdirectory(infile->filename, tmpname, FALSE))
  642.         strcat(tmpname, filename);
  643.         else {
  644.         strcpy(tmpname, filename);
  645.         }
  646.         if (access (tmpname, permissions) == 0) {
  647.                 strcpy(filename, tmpname);
  648.         return (TRUE);
  649.             }
  650.     }
  651.     /*
  652.      * Look in any directories specified by -I command line
  653.      * arguments, then in the builtin search list.
  654.      */
  655.     for (incptr = incdir; incptr < incend; incptr++) {
  656.         if (strlen(*incptr) + strlen(filename) >= (NBUFF - 1))
  657.         cfatal("Filename work buffer overflow", NULLST);
  658.         else {
  659. #if (HOST == SYS_UNIX || HOST == SYS_XENIX || HOST == SYS_AIX)
  660.         if (filename[0] == '/')
  661.             strcpy(tmpname, filename);
  662.         else {
  663.             sprintf(tmpname, "%s/%s", *incptr, filename);
  664.         }
  665. #else
  666. #if (HOST == SYS_OS2)
  667.         if ((filename[0] == '\\') || (filename[0] == '/') || (filename[1] == ':'))
  668.             strcpy(tmpname, filename);
  669.         else {
  670.             sprintf(tmpname, "%s\\%s", *incptr, filename);
  671.         }
  672. #else
  673.         if (!hasdirectory(filename, tmpname, FALSE))
  674.             sprintf(tmpname, "%s%s", *incptr, filename);
  675. #endif
  676. #endif
  677.             if (access (tmpname, permissions) == 0) {
  678.                    strcpy(filename, tmpname);
  679.            return (TRUE);
  680.                 }
  681.         }
  682.     }
  683.     return (FALSE);
  684. }
  685.  
  686. #if HOST == SYS_MVS
  687.  
  688. /* convert (unix) include string into suitable mvs string for fopen.
  689.  * "foo"             ==> "syslib(foo)"
  690.  * "foo.h"           ==> "syslib(foo)"
  691.  * "foo.hxx"         ==> "syslib(foo)"
  692.  * "foo.xxx"         ==> "xxx(foo)"
  693.  * "ddname/foo"      ==> "ddname(foo)"
  694.  * "ddname/foo.h"    ==> "ddname(foo)"
  695.  * "ddname/foo.xxx"  ==> "ddname(foo)"
  696.  *
  697.  */
  698. void parse_mvs(filename) 
  699.   char *filename;                        /* This get clobbered!!! */
  700. {
  701.   char tmpname[NBUFF];             /* Filename work area    */
  702.   char *dot, *dotstr, *slash, *memname, *sp;
  703.  
  704.   strcpy(tmpname,filename);         /* copy to work buffer */
  705.   dot   = strrchr(tmpname, '.');     /* find location of "." */
  706.   slash = strrchr(tmpname, '/');     /* find location of "/" */
  707.   dotstr = dot+1;                        /* points at string following dot */
  708.  
  709.   /* first see if a unix style directory node has been specified
  710.    * If so, terminate the string at the "/" and copy max of 8 chars.
  711.    * Note that multiple directory nodes will not work.  This overrides
  712.    * any ddname specified via the dot.
  713.    */
  714.   memname = tmpname;             /* init memname to beg of string */
  715.   if (slash != NULL) {
  716.     memname = slash+1;             /* point member name after slash  */
  717.     *slash = EOS;             /* terminate ddname at slash */
  718.     if (strlen(tmpname) > 8)         /* truncate to 8 chars */
  719.       *(tmpname+8) = EOS;
  720.     strcpy(filename,tmpname);         /* copy ddname from dir node */
  721.     if (dot != 0)             /* get rid of text beyond dot */
  722.       *dot = EOS;
  723.   }
  724.   else
  725.     /* see if a ddname has been specified (ignore .h and .hxx so
  726.      * they don't get interpretted as a ddname).
  727.      * Limit to max of 8 chars
  728.      */
  729.     if (dot != NULL) {             /* if dot found*/
  730.       *dot = EOS;                        /* terminate memname at dot */
  731.       sp = strchr(dotstr,' ');         /* see if any trailing spaces */
  732.       if (sp != NULL)             /* if there are */
  733.     *sp = EOS;             /*   get rid of them */
  734.       if ((strcmp(dotstr,"h") == 0) ||     /* ignore .h */
  735.       (strcmp(dotstr,"hxx") == 0) )  /*   or  .hxx */
  736.     strcpy(filename,"syslib");     /*  and default to syslib */
  737.       else {
  738.     if (strlen(dotstr) > 8)         /* truncate ddname to 8 chars */
  739.       *(dotstr+8) = EOS;
  740.     strcpy(filename, dotstr);     /* add ddname to string */
  741.       }
  742.     }
  743.     else
  744.       strcpy(filename,"syslib");     /* default syslib ddname */
  745.  
  746. /* Add the include file name as parenthesized member name
  747.   strcat(filename, "(" );
  748.   sp = strchr(memname,' ');         /* see if any trailing spaces */
  749.   if (sp != NULL)             /* if spaces found */
  750.     *sp = EOS;                 /*   get rid of them */
  751.   if (strlen(memname) > 8)         /* truncate to 8 chars */
  752.     *(memname+8) = EOS;
  753.   strcat(filename, memname);         /* add include name */
  754.   strcat(filename, ")" );
  755.   return;
  756. }
  757.   
  758. /* MVS does not handle a -I search list of include files.  Instead
  759.  * it will allocate one or more logical DD names which point to a cancatenated
  760.  * list of include libraries. Convert include string into suitable
  761.  * MVS style string, and see if that member is there.
  762.  */
  763. int
  764. findinclude_mvs (filename, permissions)
  765. char        *filename;        /* Input file name        */
  766. int             permissions;            /* std permission flags, R_OK, etc */
  767. {
  768.   parse_mvs(filename);
  769.   if (access (filename, permissions) == 0) 
  770.     return (TRUE);
  771.   else
  772.     return (FALSE);
  773. }
  774.  
  775.  
  776. #endif
  777.  
  778. FILE_LOCAL int
  779. hasdirectory(source, result, is_toplevel)
  780. char        *source;    /* Directory to examine            */
  781. char        *result;    /* Put directory stuff here        */
  782. int             is_toplevel;    /* return true only when a complete path */
  783. /*
  784.  * If a device or directory is found in the source filename string, the
  785.  * node/device/directory part of the string is copied to result and
  786.  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
  787.  */
  788. {
  789. #if (HOST == SYS_UNIX || HOST == SYS_XENIX || HOST == SYS_AIX)
  790.     char* tp = strrchr(source, '/');
  791.     if (is_toplevel ? (source[0] != '/') : (tp == NULL))
  792.       return (FALSE);
  793.     strncpy(result, source, tp - source + 1);
  794.     result[tp - source + 1] = EOS;
  795.     return (TRUE);
  796. #else
  797. #if (HOST == SYS_OS2)
  798.     char* tp = strrchr(source, '\\');
  799.     if (is_toplevel ? (source[0]  != '\\') : (tp == NULL))
  800.       return (FALSE);
  801.     strncpy(result, source, tp - source + 1);
  802.     result[tp - source + 1] = EOS;
  803.     return (TRUE);
  804. #else
  805. #if HOST == SYS_VMS
  806.     if (vmsparse(source, NULLST, result)
  807.      && result[0] != EOS)
  808.         return (TRUE);
  809.     else {
  810.         return (FALSE);
  811.     }
  812. #else
  813.     /*
  814.      * Random DEC operating system (RSX, RT11, RSTS/E)
  815.      */
  816.     register char        *tp;
  817.  
  818.     if ((tp = strrchr(source, ']')) == NULL
  819.      && (tp = strrchr(source, ':')) == NULL)
  820.         return (FALSE);
  821.     else {
  822.         strncpy(result, source, tp - source + 1);
  823.         result[tp - source + 1] = EOS;
  824.         return (TRUE);
  825.     }
  826. #endif
  827. #endif
  828. #endif
  829. }
  830.  
  831. #if HOST == SYS_VMS
  832.  
  833. /*
  834.  * EXP_DEV is set if a device was specified, EXP_DIR if a directory
  835.  * is specified.  (Both set indicate a file-logical, but EXP_DEV
  836.  * would be set by itself if you are reading, say, SYS$INPUT:)
  837.  */
  838. #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
  839.  
  840. FILE_LOCAL int
  841. vmsparse(source, defstring, result)
  842. char        *source;
  843. char        *defstring;    /* non-NULL -> default string.        */
  844. char        *result;    /* Size is at least NAM$C_MAXRSS + 1    */
  845. /*
  846.  * Parse the source string, applying the default (properly, using
  847.  * the system parse routine), storing it in result.
  848.  * TRUE if it parsed, FALSE on error.
  849.  *
  850.  * If defstring is NULL, there are no defaults and result gets
  851.  * (just) the node::[directory] part of the string (possibly "")
  852.  */
  853. {
  854.     struct FAB    fab = cc$rms_fab;    /* File access block    */
  855.     struct NAM    nam = cc$rms_nam;    /* File name block    */
  856.     char        fullname[NAM$C_MAXRSS + 1];
  857.     register char    *rp;            /* Result pointer    */
  858.  
  859.     fab.fab$l_nam = &nam;            /* fab -> nam        */
  860.     fab.fab$l_fna = source;            /* Source filename    */
  861.     fab.fab$b_fns = strlen(source);        /* Size of source    */
  862.     fab.fab$l_dna = defstring;        /* Default string    */
  863.     if (defstring != NULLST)
  864.         fab.fab$b_dns = strlen(defstring);    /* Size of default    */
  865.     nam.nam$l_esa = fullname;        /* Expanded filename    */
  866.     nam.nam$b_ess = NAM$C_MAXRSS;        /* Expanded name size    */
  867.     if (sys$parse(&fab) == RMS$_NORMAL) {    /* Parse away        */
  868.         fullname[nam.nam$b_esl] = EOS;    /* Terminate string    */
  869.         result[0] = EOS;            /* Just in case        */
  870.         rp = &result[0];
  871.         /*
  872.          * Remove stuff added implicitly, accepting node names and
  873.          * dev:[directory] strings (but not process-permanent files).
  874.          */
  875.         if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
  876.         if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
  877.             strncpy(result, nam.nam$l_node, nam.nam$b_node);
  878.             rp += nam.nam$b_node;
  879.             *rp = EOS;
  880.         }
  881.         if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
  882.             strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
  883.             rp += nam.nam$b_dev + nam.nam$b_dir;
  884.             *rp = EOS;
  885.         }
  886.         }
  887.         if (defstring != NULLST) {
  888.         strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
  889.         rp += nam.nam$b_name + nam.nam$b_type;
  890.         *rp = EOS;
  891.         if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
  892.             strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
  893.             rp[nam.nam$b_ver] = EOS;
  894.         }
  895.         }
  896.         return (TRUE);
  897.     }
  898.     return (FALSE);
  899. }
  900. #endif
  901.  
  902.